package fast.calc;

import fast.calc.Fast;
import fast.data.Stat;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public abstract class Attacks {
	
	protected Fast f;
	protected Stats s;
	
	protected double spellScaling;
	
	public Attacks(Fast f){
		this.f = f;
		s = f.getStats();
	}
	
	public AttacksBlock get_dmg_vial_of_shadows(){
		double damage = 5035 + 0.3 * s.getBuffed(Stat.ap);
		double crit_damage = damage * s.getCritMultiplier();
		return new AttacksBlock("vial_of_shadows",AttackType.physical, damage, crit_damage);
	}
	
	public double get_crit_vial_of_shadows(){
		double crit_chance = s.getCritPercent();
		return crit_chance;
	}
	
	public AttacksBlock get_dmg_vial_of_shadows_heroic(){
		double damage = 5682.5 + 0.339 * s.getBuffed(Stat.ap);;
		double crit_damage = damage * s.getCritMultiplier();
		return new AttacksBlock("vial_of_shadows_heroic",AttackType.physical, damage, crit_damage);
	}
	
	public double get_crit_vial_of_shadows_heroic(){
		double crit_chance = s.getCritPercent();
		return crit_chance;
	}
	
	public AttacksBlock get_dmg_vial_of_shadows_lfr(){
		double damage = 4460.5 + 0.266 * s.getBuffed(Stat.ap);;
		double crit_damage = damage * s.getCritMultiplier();
		return new AttacksBlock("vial_of_shadows_lfr",AttackType.physical, damage, crit_damage);
	}
	
	public double get_crit_vial_of_shadows_lfr(){
		double crit_chance = s.getCritPercent();
		return crit_chance;
	}
	
	public AttacksBlock get_dmg_no_kaled(){
		double damage = (7654 + 11481)/2;
		double crit_damage = damage * s.getCritMultiplier();
		return new AttacksBlock("no_kaled",AttackType.magical, damage, crit_damage);
	}
	
	public double get_crit_no_kaled(){
		double crit_chance = s.getCritPercent();
		return crit_chance;
	}
	
	public AttacksBlock get_dmg_no_kaled_heroic(){
		double damage = (8640 + 12960)/2;
		double crit_damage = damage * s.getCritMultiplier();
		return new AttacksBlock("no_kaled_heroic",AttackType.magical, damage, crit_damage);
	}
	
	public double get_crit_no_kaled_heroic(){
		double crit_chance = s.getCritPercent();
		return crit_chance;
	}
	
	public AttacksBlock get_dmg_touch_of_the_grave(){
		double avg = 8 * 1710; // LEVEL_90 ONLY
		double min = avg * ( 1 - 0.1500000060 / 2);
		double max = avg * ( 1 + 0.1500000060 / 2);
		
		double damage = (min+max)/2;
		double crit_damage = damage * s.getCritMultiplier();
		return new AttacksBlock("touch_of_the_grave",AttackType.magical,damage, crit_damage);
	}
	
	public double get_crit_touch_of_the_grave(){
		return 0;
	}
	
	public AttacksBlock get_dmg_mh_elemental_force(){
		double damage = (2775 + 3225)/2;
		double crit_damage = damage * s.getCritMultiplier();
		return new AttacksBlock("mh_elemental_force",AttackType.magical, damage, crit_damage);
	}
	
	public double get_crit_mh_elemental_force(){
		double crit_chance = s.getCritPercent();
		return crit_chance;
	}
	
	public AttacksBlock get_dmg_oh_elemental_force(){
		double damage = (2775 + 3225)/2;
		double crit_damage = damage * s.getCritMultiplier();
		return new AttacksBlock("oh_elemental_force",AttackType.magical, damage, crit_damage);
	}
	
	public double get_crit_oh_elemental_force(){
		double crit_chance = s.getCritPercent();
		return crit_chance;
	}
	
	public AttacksBlock get_dmg_capacitive_primal_diamond(){
		double damage = 280 + 0.75 * s.getBuffed(Stat.ap);
		double crit_damage = damage * s.getCritMultiplier();
		return new AttacksBlock("capacitive_primal_diamond",AttackType.magical, damage, crit_damage);
	}
	
	public double get_crit_capacitive_primal_diamond(){
		double crit_chance = s.getCritPercent();
		return crit_chance;
	}
	
	public AttacksBlock get_dmg(String attack) {
		return get_dmg(attack, 0);
	}

	public AttacksBlock get_dmg(String attack, int cps) {
		Method method;
		AttacksBlock value = null;
		try {
			if(cps > 0){
				method = this.getClass().getMethod( "get_dmg_" + attack , int.class );
				value = (AttacksBlock) method.invoke( this, cps);
			}else{
				method = this.getClass().getMethod( "get_dmg_" + attack );
				value = (AttacksBlock) method.invoke( this );
			}
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		return value;
	}
	
	public Double get_crit(String attack) {
		Method method;
		Double value = null;
		try {
			method = this.getClass().getMethod( "get_crit_" + attack );
			value = (Double) method.invoke( this );
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		return value;
	}
}
